﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Eb;
using Es;

public class DefChannelProject : ComponentDef
{
    //---------------------------------------------------------------------
    public override void defAllProp(Dictionary<string, string> map_param)
    {
    }
}

public class LoginChannelProject<T> : Component<T> where T : DefChannelProject, new()
{
    //-------------------------------------------------------------------------
    ProjectConfig mProjectConfig;
    UCenterVerify mUCenterVerify;
    Dictionary<string, LoginChannelService<DefChannelService>> mMapChannelService
        = new Dictionary<string, LoginChannelService<DefChannelService>>();// key=NodeId, 21,23...，不包含前缀
    Dictionary<string, LoginChannelService<DefChannelService>> mMapToken
        = new Dictionary<string, LoginChannelService<DefChannelService>>();// key=token
    Random mRandom = new Random();

    //-------------------------------------------------------------------------
    public LoginUCenter<DefUCenter> CoUCenter { get; private set; }
    public ProjectConfig ProjectConfig { get { return mProjectConfig; } }
    public string ProjectId { get; private set; }// "Dragon1_1.00.005"

    //-------------------------------------------------------------------------
    public override void init()
    {
        Entity et_ucenter = EntityMgr.findFirstEntityByType<EtUCenter>();
        CoUCenter = et_ucenter.getComponent<LoginUCenter<DefUCenter>>();
        ProjectId = (string)Entity.getCacheData("ProjectId");

        EbLog.Note("LoginChannelProject.init() ProjectId=" + ProjectId);

        EsEngine.Instance.ZkClient.subscribeDataChanges(CoUCenter.ZkNode4ProjectInfo + "/" + ProjectId,
            _onZkNode4ProjectReadData, null);
    }

    //-------------------------------------------------------------------------
    public override void release()
    {
        if (mUCenterVerify != null)
        {
            mUCenterVerify.stop();
            mUCenterVerify = null;
        }

        EbLog.Note("LoginChannelProject.release() ProjectId=" + ProjectId);
    }

    //-------------------------------------------------------------------------
    public override void update(float elapsed_tm)
    {
        if (mUCenterVerify == null) return;
        mUCenterVerify.update(elapsed_tm);
    }

    //-------------------------------------------------------------------------
    public override void handleEvent(object sender, EntityEvent e)
    {
    }

    //-------------------------------------------------------------------------
    // Client->UCenter，请求登陆
    public bool client2ucenterLogin(string account, string password,
        Dictionary<string, string> map_param, IRpcCallerSession client_session)
    {
        if (mUCenterVerify == null)
        {
            EbLog.Error("LoginChannelProject.client2ucenterLogin() Error! ProjectId=" + ProjectId);
            EbLog.Error("未加成成功帐号验证插件");
            return false;
        }

        // 负载均衡
        LoginChannelService<DefChannelService> co = null;
        int index = mRandom.Next(0, mMapChannelService.Count);
        int n = 0;
        foreach (var i in mMapChannelService)
        {
            if (n == index)
            {
                co = i.Value;
                break;
            }
            n++;
        }

        if (co == null)
        {
            EbLog.Error("LoginChannelProject.client2ucenterLogin() Error! ProjectId=" + ProjectId);
            EbLog.Error("为找到该Project下的服务，ServiceCount=" + mMapChannelService.Count);
            return false;
        }

        // 请求帐号验证
        EbLog.Note("登陆验证step 3 of 6: 在Project下，请求帐号验证, ProjectId=" + ProjectId + " Acc=" + account);
        LoginInfo login_info = co.client2ucenterLogin(account, password, map_param, client_session);
        mMapToken[login_info.token] = co;
        mUCenterVerify.verify(login_info.token, login_info.acc, login_info.pwd, login_info.map_param);

        return true;
    }

    //-------------------------------------------------------------------------
    // Zk读节点数据回调
    void _onZkNode4ProjectReadData(int result, string data, string[] chdn, Dictionary<string, object> param)
    {
        if (result != 0 || string.IsNullOrEmpty(data)) return;

        try
        {
            // 解析配置文件
            mProjectConfig = new ProjectConfig(data);

            // 加载登陆验证插件
            if (mProjectConfig.VerifyMode == "SOA")
            {
                mUCenterVerify = UCenterVerifyHelper.setupUCenterVerify(
                    ".\\EsUCenterVerifySOA\\bin\\EsUCenterVerifySOA.dll", "UCenterVerifySOA", mProjectConfig.VerifyConfig);
            }
            else if (mProjectConfig.VerifyMode == "DB")
            {
                mUCenterVerify = UCenterVerifyHelper.setupUCenterVerify(
                    ".\\EsUCenterVerifyMySQL\\bin\\EsUCenterVerifyMySQL.dll",
                    "UCenterVerifyMySQL", mProjectConfig.VerifyConfig);
            }

            if (mUCenterVerify != null)
            {
                mUCenterVerify.setResponse(_onVerifyResponse);
            }

            // 监听Zk项目服务节点
            EsEngine.Instance.ZkClient.subscribeChildChanges(mProjectConfig.ServiceParentNode, _onZkServiceNodeChildChanged);
        }
        catch (Exception ex)
        {
            EbLog.Error("LoginChannelProject._onZkNode4ProjectReadData() Exception: " + ex);
        }
    }

    //-------------------------------------------------------------------------
    void _onZkServiceNodeChildChanged(int result, string data, string[] chdn, Dictionary<string, object> param)
    {
        if (result != 0) return;

        Dictionary<string, string> map_project_node_remote = new Dictionary<string, string>();
        List<string> list_project_node_remote = new List<string>();
        List<string> l = null;
        if (chdn != null) l = chdn.ToList();
        else l = new List<string>();
        foreach (var i in l)
        {
            if (!i.Contains(mProjectConfig.ServiceNodeTypeString)) continue;

            string[] list_str = i.Split('_');
            int node_id = int.Parse(list_str[2]);
            list_project_node_remote.Add(node_id.ToString());
            map_project_node_remote[node_id.ToString()] = list_str[0];
        }

        List<string> list_project_node_local = mMapChannelService.Keys.ToList<string>();
        IEnumerable<string> list_add = list_project_node_remote.Except(list_project_node_local);
        IEnumerable<string> list_del = list_project_node_local.Except(list_project_node_remote);

        // 被移除的ChannelService
        foreach (var i in list_del)
        {
            LoginChannelService<DefChannelService> co = null;
            if (mMapChannelService.TryGetValue(i, out co))
            {
                EntityMgr.destroyEntity(co.Entity);
                mMapChannelService.Remove(i);
            }
        }

        // 新增的ChannelService
        foreach (var i in list_add)
        {
            Dictionary<string, object> cache_data = new Dictionary<string, object>();
            cache_data["NodeId"] = i;
            cache_data["NodeTypeString"] = ProjectConfig.ServiceNodeTypeString;
            cache_data["NodeType"] = ProjectConfig.ServiceNodeType;
            Entity et_service = EntityMgr.createEntity<EtChannelService>(cache_data, Entity);
            var co = et_service.getComponent<LoginChannelService<DefChannelService>>();
            mMapChannelService[i] = co;
        }
    }

    //-------------------------------------------------------------------------
    void _onVerifyResponse(string token, ulong acc_id, string acc, eLoginResult result, Dictionary<string, string> map_param)
    {
        EbLog.Note("登陆验证step 4 of 6: 在Project下，帐号验证完成, ProjectId="
            + ProjectId + " Acc=" + acc + " LoginResult=" + result);

        LoginChannelService<DefChannelService> co;
        if (mMapToken.TryGetValue(token, out co))
        {
            mMapToken.Remove(token);
            co.onDbVerify(token, acc_id, acc, result, map_param);
        }
        else
        {
            EbLog.Error("LoginChannelProject._onVerifyResponse() not found token=" + token);
        }
    }
}
